#include "remitable.h"

RemiTable::RemiTable()
{
    this->setColumnCount(8);
    this->setHeaderLabels(QStringList() << "Titel" << "Ausgabe" << "VK" << "Menge" << "Summe" << "Erfas.-Zeitp." << "GTIN" << "Addon");

    this->setEditTriggers(QAbstractItemView::NoEditTriggers);
    this->setDragDropMode(QAbstractItemView::InternalMove);
    this->setSelectionMode(QAbstractItemView::ExtendedSelection);
    this->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
    this->setIndentation(10);
    this->setUniformRowHeights(true);
    this->setAnimated(true);
    this->setAllColumnsShowFocus(true);
    this->setDefaultDropAction(Qt::IgnoreAction);

    db = QSqlDatabase::database();

    SpinBoxDelegate *delegate = new SpinBoxDelegate();
    this->setItemDelegateForColumn(3, delegate);

    connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(editRemi(QTreeWidgetItem*,int)));
    connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(remiEdited(QTreeWidgetItem*,int)));
    connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(markLastRemi()));
    connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SIGNAL(tableChanged()));
    connect(this, SIGNAL(tableChanged()), this, SLOT(updateView()));
}

RemiTable::~RemiTable()
{

}

/** ========== PUBLIC FUNCTIONS ========== **/

void RemiTable::loadRemiFromDatabase()
{
    if ( db.isOpen() || db.open() )
    {
        blockSignals(true);
        setEnabled(false);

        setSortingEnabled(false);
        pakete.clear();
        clear();

        QSqlQuery q("SELECT `id`, `paket_id` FROM `remission` WHERE `archiv_id` = '-1' ORDER BY `paket_id` ASC;", db);
        while ( q.next() )
        {
            if ( !pakete.contains( q.value(1).toInt() ) )
            {
                PaketItem *paket = new PaketItem(this, q.value(1).toInt());
                pakete.insert(paket->getID(), paket);
            }

            pakete[ q.value(1).toInt() ]->addChild( new RemiItem( q.value(0).toInt() ) );
        }

        if ( !pakete.contains(-1) )
            pakete.insert(-1, new PaketItem(this, -1));

        foreach ( PaketItem *i, pakete )
            addTopLevelItem(i);

        expandAll();

        setEnabled(true);
        blockSignals(false);

        emit tableChanged();
    }
}

RemiItem* RemiTable::getLastEditedRemi()
{
    if ( !pakete.isEmpty() )
    {
        RemiItem *lastremi = new RemiItem(-1);
        bool empty = false;

        foreach ( PaketItem *p, pakete )
        {
            if ( p->getRemiItems().count() == 0 )
                empty = true;
            else
                empty = false;

            foreach ( RemiItem *r, p->getRemiItems() )
            {
                if ( r->getLastEdit() > lastremi->getLastEdit() )
                {
                    lastremi = r;
                }
            }
        }

        if ( empty )
            return 0;
        else
            return lastremi;
    }

    return 0;
}

void RemiTable::addRemi(QString gtin, QString addon, int menge)
{
    foreach ( RemiItem *r, pakete[-1]->getRemiItems() )
    {
        if ( r->getGTIN() == gtin && r->getAddon() == addon )
        {
            r->addQuantity(menge);
            emit tableChanged();
            return;
        }
    }

    RemiItem *remi = new RemiItem( gtin, addon, menge );
    pakete[-1]->addRemi(remi);
    emit tableChanged();
}

RemiItem* RemiTable::getRemi(int id)
{
    foreach ( PaketItem *paket, pakete )
    {
        foreach ( RemiItem *remi, paket->getRemiItems() )
        {
            if ( remi->getID() == id )
            {
                return remi;
            }
        }
    }
    return new RemiItem(-1);
}

PaketItem* RemiTable::getPaket(int id)
{
    return pakete[ id ];
}


/** ========== PUBLIC SLOTS ========== **/

void RemiTable::removeSelectedRemis()
{
    blockSignals(true);
    setEnabled(false);

    db.transaction();
    foreach ( QTreeWidgetItem *i, selectedItems() )
    {
        RemiItem *r = static_cast<RemiItem*>(i);
        pakete[ r->getPaket() ]->deleteRemi(r);
    }
    db.commit();

    setEnabled(true);
    blockSignals(false);

    emit tableChanged();
}


void RemiTable::showEvent(QShowEvent *)
{
    loadRemiFromDatabase();
}

/** ========== Drag & Drop ========== **/

void RemiTable::dragMoveEvent(QDragMoveEvent *event)
{
    // Wenn über einem Remi-Element, dann zulassen
    // Wenn über einem Paket-Element, dann nur zulassen, wenn nicht am oberen oder uneren Rand,
    // damit es nicht als Root-Element eingefügt wird
    if ( itemAt( event->pos() ) && ( itemAt( event->pos() )->parent() || visualItemRect( itemAt( event->pos() ) ).adjusted(0, 2, 0, -2).contains(event->pos()) ) )
    {
        event->accept();
        QTreeWidget::dragMoveEvent(event);
    }
    else
    {
        event->ignore();
    }
}

void RemiTable::dropEvent(QDropEvent *event)
{
    int neues_paket = -1;
    if ( itemAt( event->pos() )->parent() )
    {
        /** Es wurde auf eine Remi gedropt **/
        neues_paket = static_cast<PaketItem*>(itemAt( event->pos() )->parent())->getID();
    }
    else
    {
        /** Es wurde auf ein Paket gedropt **/
        neues_paket = static_cast<PaketItem*>(itemAt( event->pos() ))->getID();
    }

    if ( event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist") )
    {
        /** Decodiert die gedropten Daten und ändert die Paketnummer für die entsprechenden Remis **/
        QByteArray encoded = event->mimeData()->data("application/x-qabstractitemmodeldatalist");
        QDataStream stream(&encoded, QIODevice::ReadOnly);
        db.transaction();
        while (!stream.atEnd())
        {
            int row, col;
            QMap<int,  QVariant> roleDataMap;
            stream >> row >> col >> roleDataMap;

            if ( col == 0 ) // In der ersten Spalte ist die ID hinterlegt
            {
                RemiItem *remi = getRemi(QVariant(roleDataMap.value(Qt::UserRole)).toInt());
                pakete[ remi->getPaket() ]->removeChild( remi );
                pakete[ neues_paket ]->addRemi(remi);
            }
        }
        db.commit();
    }

    emit tableChanged();
}

bool RemiTable::newPackage()
{
    if ( db.isOpen() || db.open() )
    {
        QString paket = "";
        QSqlQuery p("SELECT `paket_id`, `datetime` FROM `remission` WHERE `paket_id` != '-1' ORDER BY `datetime` DESC LIMIT 1;", db);
        if ( p.first() )
        {
            paket = QVariant(p.value(0).toInt() + 1).toString();
            p.exec("SELECT `paket_id` FROM `remission` WHERE `paket_id` = '" + paket + "' LIMIT 1;");
            if ( p.first() )
            {
                p.exec("SELECT `paket_id`, FROM `remission` ORDER BY `paket_id` DESC LIMIT 1;");
                if ( p.first() )
                {
                    paket = QVariant(p.value(0).toInt() + 1).toString();
                }
            }
        }

        bool ok, used, isNumber;
        do
        {
            //QApplication::beep();
            paket = QInputDialog::getText(this, tr("Paket schließen"), tr("Bitte geben Sie die Nummer des aktuellen Pakets ein:"), QLineEdit::Normal, paket, &ok);

            paket.toDouble(&isNumber);
            if ( ok && !isNumber )
            {
                QMessageBox::information(this, tr("Paket"), tr("Bitte geben Sie eine gültige Nummer ein."));
                continue;
            }

            paket = (da.isGTIN(paket))?paket.mid(8,4):paket;

            QSqlQuery p("SELECT `paket_id` FROM `remission` WHERE `paket_id` = '" + paket + "';", db);
            if ( p.first() )
            {
                p.exec("SELECT `archiv_id` FROM `remission` WHERE `paket_id` = '" + paket + "';");
                if ( p.first() && p.value(0).toInt() == -1 )
                {
                    if ( QMessageBox::question(this, tr("Paket"), tr("Diese Paketnummer wird schon verwendet. Remission mit diesem Paket zusammenführen?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes )
                    {
                        used = false;
                    }
                }
                else
                {
                    QMessageBox::information(this, tr("Paket"), tr("Diese Paketnummer wurde in einer abgeschlossenen Remission verwendet. Bitte geben Sie eine neue Paketnummer ein."));
                    used = true;
                    continue;
                }
            }
            else
            {
                used = false;
            }
        }
        while ( ok && used );

        if ( ok )
        {
            /** Wenn das Paket noch nicht existiert, dann neu anlegen, sonst zum bestehenden Paket hinzufügen **/
            if ( !pakete[ paket.toInt() ] )
            {
                PaketItem *p = new PaketItem(this, paket.toInt());
                pakete.insert(p->getID(), p);
                addTopLevelItem(p);
                expandAll();
            }

            /** Jedes Remi-Item im alten Paket löschen und zum neuen Paket hinzufügen **/
            db.transaction();
            foreach ( RemiItem *remi, pakete[-1]->getRemiItems() )
            {
                pakete[ remi->getPaket() ]->removeChild( remi );
                pakete[ paket.toInt() ]->addRemi(remi);
            }
            db.commit();
        }
        else
        {
            QMessageBox::information(this, tr("Paket"), tr("Das Paket wurde nicht angelegt."));
            return false;
        }

        emit tableChanged();
        return true;
    }
    return false;
}


/** ========== PRIVATE SLOTS ========== **/

void RemiTable::editRemi(QTreeWidgetItem *item, int column)
{
    if ( column == 3 || column == 0 )
        editItem(item, column);
}


void RemiTable::remiEdited(QTreeWidgetItem *item, int column)
{
    /** Prüfen, ob es ein RemiItem ist und die erste Spalte geändert wurde **/
    if ( item->parent() && column == 0 )
    {
        RemiItem *remi = static_cast<RemiItem*>(item);

        /** Anbieten, den Titel in den Stammdaten zu ändern **/
        if ( db.isOpen() || db.open() )
        {
            QSqlQuery q(db);
            q.prepare("SELECT * FROM stammdaten WHERE `titel` != :title AND `objektnr` = :objektnr;");
            q.bindValue(":title", remi->getTitle());
            q.bindValue(":objektnr", da.getObjektNr(remi->getGTIN(), remi->getAddon()));

            if ( q.exec() && q.first() && QMessageBox::question(this, tr("Titel ändern"), tr("Soll der Titel auch in den Stammdaten geändert werden?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes )
            {
                q.prepare("UPDATE `stammdaten` SET `titel` = :titel WHERE `objektnr` = :objektnr;");
                q.bindValue(":titel", remi->getTitle());
                q.bindValue(":objektnr", da.getObjektNr(remi->getGTIN(), remi->getAddon()));
                q.exec();
                q.finish();
            }
        }

        /** Anbieten, den Titel in der aktuellen Remission zu ändern **/
        bool rename = false;
        db.transaction();
        foreach ( PaketItem *p, pakete )
        {
            foreach ( RemiItem *r, p->getRemiItems() )
            {
                if ( da.getObjektNr(r->getGTIN(), r->getAddon()) == da.getObjektNr(remi->getGTIN(), remi->getAddon()) && r->getTitle() != remi->getTitle() )
                {
                    if ( rename == true || QMessageBox::question(this, tr("Remission ändern"), tr("Soll der Titel in der aktuellen Remission geändert werden?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes )
                    {
                        rename = true;
                        r->setTitle( remi->getTitle() );
                    }
                    else
                        break;
                }
            }
        }
        db.commit();
    }
}

void RemiTable::updateView()
{
    sortByColumn(7, Qt::AscendingOrder); /** Nach Addon sortieren **/
    sortByColumn(0, Qt::AscendingOrder); /** Nach Titel sortieren **/
    for ( int i=0; i < columnCount(); i++ )
        resizeColumnToContents(i);

    markLastRemi();
}

void RemiTable::markLastRemi()
{
    blockSignals(true);
    foreach ( PaketItem *p, pakete )
    {
        foreach ( RemiItem *remi, p->getRemiItems() )
        {
            if (remi)
                remi->setHighlighted(false);
        }
    }

    if ( getLastEditedRemi() )
    {
        getLastEditedRemi()->setHighlighted(true);
        scrollToItem(getLastEditedRemi(), QAbstractItemView::EnsureVisible);
    }
    blockSignals(false);
}
